#ifndef _S3C2440_H
#define _S3C2440_H

#include <types.h>
#include <arch/cpu/soc/memory.h>

enum s3c2440_uarts {
	S3C2440_UART0	= 0,
	S3C2440_UART1	= 1,
	S3C2440_UART2	= 2
};

/* Memory Controller */ 
struct s3c2440_mem {
    uint32_t bwscon;
    uint32_t bankcon[8];
    uint32_t refresh;
    uint32_t banksize;
    uint32_t mrsrb6;
    uint32_t mrsrb7;
};

/* NAND Flash Controller */
struct s3c2440_nand {
    uint32_t nfconf;
    uint32_t nfcont;
    uint32_t nfcmd;
    uint32_t nfaddr;
    uint32_t nfdata;
    uint32_t nfmeccd0;
    uint32_t nfmeccd1;
    uint32_t nfseccd;
    uint32_t nfstat;
    uint32_t nfestat0;
    uint32_t nfestat1;
	uint32_t nfmecc0;
	uint32_t nfmecc1;
	uint32_t nfsecc;
	uint32_t nfsblk;
	uint32_t nfeblk;
};

/* Clock & Power Management */
struct s3c2440_clock_power {
    uint32_t locktime;
    uint32_t mpllcon;
    uint32_t upllcon;
    uint32_t clkcon;
    uint32_t clkslow;
    uint32_t clkdivn;
    uint32_t camdivn;
};

/* UART */
struct s3c2440_uart {
    uint32_t ulcon;
    uint32_t ucon;
    uint32_t ufcon;
    uint32_t umcon;
    uint32_t utrstat;
    uint32_t uerstat;
    uint32_t ufstat;
    uint32_t umstat;
    uint8_t  utxh;
    uint8_t  _reserved1[3];
    uint8_t  urxh;
    uint8_t  _reserved2[3];
    uint32_t ubrdiv;
};

/* Watchdog Timer */ 
struct s3c2440_wdt {
    uint32_t wtcon;
    uint32_t wtdat;
    uint32_t wtcnt;
};

/* I/O Ports */
struct s3c2440_gpio {
    uint32_t gpacon;
    uint32_t gpadat;
	uint32_t reserved1[2];

    uint32_t gpbcon;
    uint32_t gpbdat;
    uint32_t gpbup;
	uint32_t reserved2[1];

    uint32_t gpccon;
    uint32_t gpcdat;
    uint32_t gpcup;
	uint32_t reserved3[1];

    uint32_t gpdcon;
    uint32_t gpddat;
    uint32_t gpdup;
	uint32_t reserved4[1];

    uint32_t gpecon;
    uint32_t gpedat;
    uint32_t gpeup;
	uint32_t reserved5[1];

    uint32_t gpfcon;
    uint32_t gpfdat;
    uint32_t gpfup;
	uint32_t reserved6[1];

    uint32_t gpgcon;
    uint32_t gpgdat;
    uint32_t gpgup;
	uint32_t reserved7[1];

    uint32_t gphcon;
    uint32_t gphdat;
    uint32_t gphup;
	uint32_t reserved8[1];

    uint32_t misccr;
	uint32_t dclkcon;
    uint32_t extint[3];
	uint32_t eintflt[4];
	uint32_t eintmask;
	uint32_t eintpend;

	uint32_t gstatus[5];

	uint32_t reserved9[1];
	uint32_t dsc[2];
	uint32_t mslcon;

    uint32_t gpjcon;
    uint32_t gpjdat;
    uint32_t gpjup;
	uint32_t reserved10[1];
};

/* PWM Timer */
struct s3c2440_timer {
    uint32_t tcntb;
    uint32_t tcmpb;
    uint32_t tcnto;
};

struct s3c2440_timers {
    uint32_t tcfg0;
    uint32_t tcfg1;
    uint32_t tcon;
    struct s3c2440_timer ch[4];
    uint32_t tcntb4;
    uint32_t tcnto4;
};

/* RTC */
struct s3c2440_rtc {
    u8  res0[64];
    u8  rtccon;
    u8  res1[3];
    u8  ticnt;
    u8  res2[11];
    u8  rtcalm;
    u8  res3[3];
    u8  almsec;
    u8  res4[3];
    u8  almmin;
    u8  res5[3];
    u8  almhour;
    u8  res6[3];
    u8  almdate;
    u8  res7[3];
    u8  almmon;
    u8  res8[3];
    u8  almyear;
    u8  res9[3];
    u8  rtcrst;
    u8  res10[3];
    u8  bcdsec;
    u8  res11[3];
    u8  bcdmin;
    u8  res12[3];
    u8  bcdhour;
    u8  res13[3];
    u8  bcddate;
    u8  res14[3];
    u8  bcdday;
    u8  res15[3];
    u8  bcdmon;
    u8  res16[3];
    u8  bcdyear;
    u8  res17[3];
};

/* Interrupt Controller */
struct s3c2440_interrupt {
    u32 srcpnd;
    u32 intmod;
    u32 intmsk;
    u32 priority;
    u32 intpnd;
    u32 intoffset;
    u32 subsrcpnd;
    u32 intsubmsk;
};

static inline struct s3c2440_mem *s3c2440_get_base_memctl(void)
{
#if defined(__TOP_HALF__) 
	return (struct s3c2440_mem *)S3C2440_PA_MEMCTRL;
#else
	return (struct s3c2440_mem *)(__va(S3C2440_PA_MEMCTRL));
#endif
}

static inline struct s3c2440_nand *s3c2440_get_base_nandctl(void)
{
#if defined(__TOP_HALF__) 
	return (struct s3c2440_nand*)S3C2440_PA_NAND;
#else
	return (struct s3c2440_nand*)(__va(S3C2440_PA_NAND));
#endif
}

static inline struct s3c2440_clock_power *s3c2440_get_base_clock_power(void)
{
#if defined(__TOP_HALF__) 
	return (struct s3c2440_clock_power *)S3C2440_PA_CLKPWR;
#else
	return (struct s3c2440_clock_power *)(__va(S3C2440_PA_CLKPWR));
#endif
}

static inline struct s3c2440_wdt *s3c2440_get_base_wdt(void)
{
#if defined(__TOP_HALF__) 
	return (struct s3c2440_wdt *)S3C2440_PA_WATCHDOG;
#else
	return (struct s3c2440_wdt *)(__va(S3C2440_PA_WATCHDOG));
#endif
}

static inline struct s3c2440_uart *s3c2440_get_base_uart(uint32_t n)
{
#if defined(__TOP_HALF__)
	return (struct s3c2440_uart *)(S3C2440_PA_UART + (n * S3C2440_UART_OFFSET));
#else
	return (struct s3c2440_uart *)(__va(S3C2440_PA_UART + (n * S3C2440_UART_OFFSET)));
#endif
}

static inline struct s3c2440_timers *s3c2440_get_base_timers(void)
{
#if defined(__TOP_HALF__)
	return (struct s3c2440_timers *)S3C2440_PA_TIMER;
#else
	return (struct s3c2440_timers *)(__va(S3C2440_PA_TIMER));
#endif
}

static inline struct s3c2440_gpio *s3c2440_get_base_gpio(void)
{
#if defined(__TOP_HALF__) 
	return (struct s3c2440_gpio *)S3C2440_PA_GPIO;
#else
	return (struct s3c2440_gpio *)(__va(S3C2440_PA_GPIO));
#endif
}

static inline struct s3c2440_rtc *s3c2440_get_base_rtc(void)
{
#if defined(__TOP_HALF__)  
    return (struct s3c2440_rtc *)S3C2440_PA_RTC;
#else
    return (struct s3c2440_rtc *)(__va(S3C2440_PA_RTC));
#endif
}

static inline struct s3c2440_interrupt *s3c2440_get_base_interrupt(void)
{
#if defined(__TOP_HALF__)  
    return (struct s3c2440_interrupt *)S3C2440_PA_IRQ;
#else
    return (struct s3c2440_interrupt *)(__va(S3C2440_PA_IRQ));
#endif
}

#endif /* _S3C2440_H */

